home *** CD-ROM | disk | FTP | other *** search
- From: genrad!decvax!decwrl!dec-rhea!dec-pauper!minow (Martin Minow)
- Subject: archx: suggested replacement for shar
- Newsgroups: mod.sources
- Approved: jpn@panda.UUCP
-
- Mod.sources: Volume 4, Issue 80
- Submitted by: decvax!decwrl!dec-rhea!dec-pauper!minow (Martin Minow)
-
- [
- This is one of two submissions of programs that provide alternatives to
- "shar" as a source archive format. This does not imply my support of
- one format over another. Oh, I am distributing these in "shar" format
- to avoid the chicken-or-egg problem.
- - John Nelson - moderator, mod.sources
- ]
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create the files:
- # readme.txt
- # archc.c
- # archx.c
- # This archive created: Thu May 1 08:33:31 1986
- export PATH; PATH=/bin:$PATH
- echo shar: extracting "'readme.txt'" '(1420 characters)'
- if test -f 'readme.txt'
- then
- echo shar: will not over-write existing file "'readme.txt'"
- else
- cat << \SHAR_EOF > 'readme.txt'
- This is a suggested replacement for shar. It is based on
- the archive program in Kernighan and Plauger's Software Tools,
- but has been heavily simplified.
-
- It has the following advantages over shar:
-
- 1. it is not tied to Unix -- thus VMS users can unpack files without
- excessive effort. Archc and archx should run without change on
- all Unix and Unix lookalike systems, as well as on VMS (VaxC)
- and all PDP-11 Decus C systems. It has been in use for over 6
- years.
-
- 2. it does not execute the distributed image, but interprets it. This
- means that trojan horses cannot be concealed in distributions.
-
- 3 The distribution file can be edited without damaging the archive.
- (Also, embedded archives can be handled).
-
- It has the following disadvantages:
-
- 1. It is not as flexible as shar -- it cannot create directories or
- access any other Unix system services.
-
- 2. There is no checksum capability (it appears impossible to implement
- checksumming in a system-independent manner).
-
- To use, save this message. Then, use your favorite editor to extract
- archx.c (delimited by lines beginning with "-h-" in column 1). Then
- compile archx and run it using the command:
- archx <this_file>
- It should produce readme.txt, archx.c, and archc.c.
- Manual pages can be produced by extracting the text delimited by
- #ifdef DOCUMENTATION
- ...
- #endif
-
- Please report problems to the author:
-
- Martin Minow
- decvax!minow
-
- SHAR_EOF
- if test 1420 -ne "`wc -c < 'readme.txt'`"
- then
- echo shar: error transmitting "'readme.txt'" '(should have been 1420 characters)'
- fi
- fi
- echo shar: extracting "'archc.c'" '(7759 characters)'
- if test -f 'archc.c'
- then
- echo shar: will not over-write existing file "'archc.c'"
- else
- cat << \SHAR_EOF > 'archc.c'
- /*
- * A R C H I V E
- *
- * Create an archive
- *
- */
-
- /*)BUILD $(TKBOPTIONS) = {
- TASK = ...ARC
- }
- */
-
- #ifdef DOCUMENTATION
-
- title archc text file archive creation
- index text file archive creation
-
- synopsis
-
- archc file[s] >archive
-
- description
-
- Archc manages archives (libraries) of source files, allowing
- a large number of small files to be stored without using
- excessive system resources. It copies the set of named
- files to standard output in archive format.
-
- The archx program will recreate the files from an archive.
-
- Note: there are no checks against the same file appearing
- twice in an archive.
-
- archive file format
-
- Archive files are standard text files. Each archive element is
- preceeded by a line of the format:
- .s.nf
- -h- file.name date true_path_name
- .s.f
- Note that there is no line or byte count. To prevent problems,
- a '-' at the beginning of a record within a user file or embedded
- archive will be "quoted" by doubling it. The date and true filename
- fields are ignored. On Dec operating systems, file.name is
- forced to lowercase. Certain bytes at the beginning of a record are
- also prefixed by '-' to prevent mailers from treating them
- as commands.
-
- diagnostics
-
- Diagnostic messages should be self-explanatory
-
- author
-
- Martin Minow
-
- #endif
-
- #include <stdio.h>
- #include <ctype.h>
- #ifdef vms
- #include <ssdef.h>
- #include <stsdef.h>
- #define IO_SUCCESS (SS$_NORMAL | STS$M_INHIB_MSG)
- #define IO_ERROR SS$_ABORT
- #endif
- /*
- * Note: IO_SUCCESS and IO_ERROR are defined in the Decus C stdio.h file
- */
- #ifndef IO_SUCCESS
- #define IO_SUCCESS 0
- #endif
- #ifndef IO_ERROR
- #define IO_ERROR 1
- #endif
- #define EOS 0
- #define FALSE 0
- #define TRUE 1
-
- char text[513]; /* Working text */
- char name[81]; /* Current archive member name */
- char pathname[81]; /* Output for argetname() */
- char *timetext; /* Time of day text */
- int verbose = TRUE; /* TRUE for verbosity */
- FILE *infd; /* Input file */
-
- main(argc, argv)
- int argc; /* Arg count */
- char *argv[]; /* Arg vector */
- {
- register int i; /* Random counter */
- register char *fn; /* File name pointer */
- register char *argp; /* Arg pointer */
- int nfiles;
- extern char *ctime();
- extern long time();
- long timval;
-
- time(&timval);
- timetext = ctime(&timval);
- timetext[24] = EOS;
- #ifdef vms
- argc = getredirection(argc, argv);
- #endif
- if (argc <= 1)
- fprintf(stderr, "No files to archive?\n");
- #ifdef unix
- for (i = 1; i < argc; i++) {
- if ((infd = fopen(argv[i], "r")) == NULL)
- perror(argv[i]);
- else {
- strcpy(pathname, argv[i]);
- import();
- fclose(infd);
- }
- }
- #else
- /*
- * Decus C supports fwild/fnext for explicit processing
- * of wild-card filenames.
- */
- for (i = 1; i < argc; i++) {
- if ((infd = fwild(argv[i], "r")) == NULL)
- perror(argv[i]);
- else {
- for (nfiles = 0; fnext(infd) != NULL; nfiles++) {
- fgetname(infd, pathname);
- import();
- }
- fclose(infd);
- if (nfiles == 0)
- fprintf(stderr, "No files match \"%s\"\n", argv[i]);
- }
- }
- #endif
- }
-
- import()
- /*
- * Add the file open on infd (with file name in pathname) to
- * the archive.
- */
- {
- unsigned int nrecords;
-
- fixname();
- nrecords = 0;
- printf("-h- %s\t%s\t%s\n", name, timetext, pathname);
- while (fgets(text, sizeof text, infd) != NULL) {
- switch (text[0]) {
- case '-':
- case '.':
- case '~':
- putchar('-'); /* Quote */
- }
- fputs(text, stdout);
- nrecords++;
- }
- if (ferror(infd)) {
- perror(name);
- fprintf(stderr, "Error when importing a file\n");
- }
- if (verbose) {
- fprintf(stderr, "%u records read from %s\n",
- nrecords, pathname);
- }
- }
-
- fixname()
- /*
- * Get file name (in pathname), stripping off device:[directory]
- * and ;version. The archive name ("file.ext") is written to name[].
- * On a dec operating system, name is forced to lowercase.
- */
- {
- register char *tp;
- register char *ip;
- char bracket;
- extern char *strrchr();
-
- #ifdef unix
- /*
- * name is after all directory information
- */
- if ((tp = strrchr(pathname, '/')) != NULL)
- tp++;
- else
- tp = pathname;
- strcpy(name, tp);
- #else
- strcpy(name, pathname);
- if ((tp = strrchr(name, ';')) != NULL)
- *tp = EOS;
- while ((tp = strchr(name, ':')) != NULL)
- strcpy(name, tp + 1);
- switch (name[0]) {
- case '[': bracket = ']';
- break;
- case '<': bracket = '>';
- break;
- case '(': bracket = ')';
- break;
- default: bracket = EOS;
- break;
- }
- if (bracket != EOS) {
- if ((tp = strchr(name, bracket)) == NULL) {
- fprintf(stderr, "? Illegal file name \"%s\"\n",
- pathname);
- }
- else {
- strcpy(name, tp + 1);
- }
- }
- for (tp = name; *tp != EOS; tp++) {
- if (isupper(*tp))
- *tp = tolower(*tp);
- }
- #endif
- }
-
- #ifdef unix
- char *
- strrchr(stng, chr)
- register char *stng;
- register char chr;
- /*
- * Return rightmost instance of chr in stng.
- * This has the wrong name on some Unix systems.
- */
- {
- register char *result;
-
- result = NULL;
-
- do {
- if (*stng == chr)
- result = stng;
- } while (*stng++ != EOS);
- return (result);
- }
- #endif
-
- /*
- * getredirection() is intended to aid in porting C programs
- * to VMS (Vax-11 C) which does not support '>' and '<'
- * I/O redirection. With suitable modification, it may
- * useful for other portability problems as well.
- */
-
- static int
- getredirection(argc, argv)
- int argc;
- char **argv;
- /*
- * Process vms redirection arg's. Exit if any error is seen.
- * If getredirection() processes an argument, it is erased
- * from the vector. getredirection() returns a new argc value.
- *
- * Warning: do not try to simplify the code for vms. The code
- * presupposes that getredirection() is called before any data is
- * read from stdin or written to stdout.
- *
- * Normal usage is as follows:
- *
- * main(argc, argv)
- * int argc;
- * char *argv[];
- * {
- * argc = getredirection(argc, argv);
- * }
- */
- {
- #ifdef vms
- register char *ap; /* Argument pointer */
- int i; /* argv[] index */
- int j; /* Output index */
- int file; /* File_descriptor */
-
- for (j = i = 1; i < argc; i++) { /* Do all arguments */
- switch (*(ap = argv[i])) {
- case '<': /* <file */
- if (freopen(++ap, "r", stdin) == NULL) {
- perror(ap); /* Can't find file */
- exit(IO_ERROR); /* Is a fatal error */
- }
-
- case '>': /* >file or >>file */
- if (*++ap == '>') { /* >>file */
- /*
- * If the file exists, and is writable by us,
- * call freopen to append to the file (using the
- * file's current attributes). Otherwise, create
- * a new file with "vanilla" attributes as if
- * the argument was given as ">filename".
- * access(name, 2) is TRUE if we can write on
- * the specified file.
- */
- if (access(++ap, 2) == 0) {
- if (freopen(ap, "a", stdout) != NULL)
- break; /* Exit case statement */
- perror(ap); /* Error, can't append */
- exit(IO_ERROR); /* After access test */
- } /* If file accessable */
- }
- /*
- * On vms, we want to create the file using "standard"
- * record attributes. create(...) creates the file
- * using the caller's default protection mask and
- * "variable length, implied carriage return"
- * attributes. dup2() associates the file with stdout.
- */
- if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1
- || dup2(file, fileno(stdout)) == -1) {
- perror(ap); /* Can't create file */
- exit(IO_ERROR); /* is a fatal error */
- } /* If '>' creation */
- break; /* Exit case test */
-
- default:
- argv[j++] = ap; /* Not a redirector */
- break; /* Exit case test */
- }
- } /* For all arguments */
- return (j);
- #else
- /*
- * Note: argv[] is referenced to fool the Decus C
- * syntax analyser, supressing an unneeded warning
- * message.
- */
- return (argv[0], argc); /* Just return as seen */
- #endif
- }
-
-
-
- SHAR_EOF
- if test 7759 -ne "`wc -c < 'archc.c'`"
- then
- echo shar: error transmitting "'archc.c'" '(should have been 7759 characters)'
- fi
- fi
- echo shar: extracting "'archx.c'" '(7837 characters)'
- if test -f 'archx.c'
- then
- echo shar: will not over-write existing file "'archx.c'"
- else
- cat << \SHAR_EOF > 'archx.c'
- /*
- * A R C H X
- *
- * Archive extraction
- *
- */
-
- /*
- * Note: the )BUILD comment is extracted by a Decus C tool to construct
- * system-dependent compiler command lines.
- *
- * Text inside #ifdef DOCUMENTATION is converted to runoff by a
- * Decus C tool.
- */
-
- /*)BUILD $(TKBOPTIONS) = {
- TASK = ...ARX
- }
- */
-
- #ifdef DOCUMENTATION
-
- title archx text file archiver extraction
- index text file archiver extraction
-
- synopsis
-
- archx archive_files
-
- description
-
- Archx manages archives (libraries) of source files, allowing
- a large number of small files to be stored without using
- excessive system resources. Archx extracts all files from
- an archive.
-
- If no archive_name file is given, the standard input is read.
- Archive header records are echoed to the standard output.
-
- archive file format
-
- Archive files are standard text files. Each archive element is
- preceeded by a line of the format:
- .s.nf
- -h- file.name date true_name
- .s.f
- Note that there is no line or byte count. To prevent problems,
- a '-' at the beginning of a record within a user file or embedded
- archive will be "quoted" by doubling it. The date and true filename
- fields are ignored. On some operating systems, file.name is
- forced to lowercase. The archive builder (archc) may prefix
- other characters by '-'.
-
- If the first non-blank line of an input file does not
- begin with "-h", the text will be appended to "archx.tmp"
- This is needed if archives are distributed by mail
- and arrive with initial routing and subject information.
-
- diagnostics
-
- Diagnostic messages should be self-explanatory
-
- author
-
- Martin Minow
-
- bugs
-
- #endif
-
- #include <stdio.h>
- #include <ctype.h>
- #ifdef vms
- #include <ssdef.h>
- #include <stsdef.h>
- #define IO_SUCCESS (SS$_NORMAL | STS$M_INHIB_MSG)
- #define IO_ERROR SS$_ABORT
- #endif
- /*
- * Note: IO_SUCCESS and IO_ERROR are defined in the Decus C stdio.h file
- */
- #ifndef IO_SUCCESS
- #define IO_SUCCESS 0
- #endif
- #ifndef IO_ERROR
- #define IO_ERROR 1
- #endif
-
- #define EOS 0
- #define FALSE 0
- #define TRUE 1
-
- /*
- * The following status codes are returned by gethdr()
- */
- #define DONE 0
- #define GOTCHA 1
- #define NOGOOD 2
-
- char text[513]; /* Working text line */
- char name[81]; /* Current archive member name */
- char filename[81]; /* Working file name */
- char arfilename[81]; /* Archive file name */
- char fullname[81]; /* Output for argetname() */
- int verbose = TRUE; /* TRUE for verbosity */
- int first_archive; /* For mail header skipping */
-
- main(argc, argv)
- int argc; /* Arg count */
- char *argv[]; /* Arg vector */
- {
- register int i; /* Random counter */
- int status; /* Exit status */
-
- #ifdef vms
- argc = getredirection(argc, argv);
- #endif
- status = IO_SUCCESS;
- if (argc == 1)
- process();
- else {
- for (i = 1; i < argc; i++) {
- if (freopen(argv[i], "r", stdin) != NULL)
- process();
- else {
- perror(argv[i]);
- status = IO_ERROR;
- }
- }
- }
- exit(status);
- }
-
- process()
- /*
- * Process archive open on stdin
- */
- {
- register char *fn; /* File name pointer */
- register FILE *outfd;
- register int i;
-
- text[0] = EOS;
- while ((i = gethdr()) != DONE) {
- switch (i) {
- case GOTCHA:
- if ((outfd = fopen(name, "w")) == NULL) {
- perror(name);
- fprintf(stderr, "Can't create \"%s\"\n", name);
- arskip();
- continue;
- }
- break;
-
- case NOGOOD:
- fprintf(stderr, "Missing -h-, writing to archx.tmp\n");
- fprintf(stderr, "Current text line: %s", text);
- strcpy(name, "archx.tmp");
- if ((outfd = fopen(name, "a")) == NULL) {
- perror(name);
- fprintf(stderr, "Cannot append to %s\n", name);
- arskip();
- continue;
- }
- break;
- }
- arexport(outfd);
- fclose(outfd);
- }
- }
-
- int
- gethdr()
- /*
- * If text is null, read a record, returning to signal input state:
- * DONE Eof read
- * NOGOOD -h- wasn't first non-blank line. Line is in text[]
- * GOTCHA -h- found, parsed into name.
- */
- {
- register char *tp;
- register char *np;
-
- again: if (text[0] == EOS
- && fgets(text, sizeof text, stdin) == NULL)
- return (DONE);
- if (text[0] == '\n' && text[1] == EOS) {
- text[0] = EOS;
- goto again;
- }
- if (text[0] != '-'
- || text[1] != 'h'
- || text[2] != '-')
- return (NOGOOD);
- for (tp = &text[3]; isspace(*tp); tp++)
- ;
- for (np = name; !isspace(*tp); *np++ = *tp++)
- ;
- *np = EOS;
- return (GOTCHA);
- }
-
- arskip()
- /*
- * Skip to next header
- */
- {
- while (fgets(text, sizeof text, stdin) != NULL) {
- if (text[0] == '-' && text[1] == 'h' && text[2] == '-')
- return;
- }
- text[0] = EOS; /* EOF signal */
- }
-
- arexport(outfd)
- register FILE *outfd;
- /*
- * Read secret archive format, writing archived data to outfd.
- * Clean out extraneous <cr>,<lf>'s
- */
- {
- register char *tp;
- unsigned int nrecords;
-
- printf("Creating \"%s\", ", name);
- nrecords = 0;
- while (fgets(text, sizeof text, stdin) != NULL) {
- tp = &text[strlen(text)];
- if (tp > &text[1] && *--tp == '\n' && *--tp == '\r') {
- *tp++ = '\n';
- *tp = EOS;
- }
- if (text[0] == '-') {
- if (text[1] == 'h')
- goto gotcha;
- fputs(text+1, outfd);
- }
- else {
- fputs(text, outfd);
- }
- nrecords++;
- }
- text[0] = EOS;
- gotcha: printf("%u records\n", nrecords);
- if (ferror(stdin) || ferror(outfd))
- printf("Creation of \"%s\" completed with error\n", name);
- }
-
- /*
- * getredirection() is intended to aid in porting C programs
- * to VMS (Vax-11 C) which does not support '>' and '<'
- * I/O redirection. With suitable modification, it may
- * useful for other portability problems as well.
- */
-
- #ifdef vms
- static int
- getredirection(argc, argv)
- int argc;
- char **argv;
- /*
- * Process vms redirection arg's. Exit if any error is seen.
- * If getredirection() processes an argument, it is erased
- * from the vector. getredirection() returns a new argc value.
- *
- * Warning: do not try to simplify the code for vms. The code
- * presupposes that getredirection() is called before any data is
- * read from stdin or written to stdout.
- *
- * Normal usage is as follows:
- *
- * main(argc, argv)
- * int argc;
- * char *argv[];
- * {
- * argc = getredirection(argc, argv);
- * }
- */
- {
- register char *ap; /* Argument pointer */
- int i; /* argv[] index */
- int j; /* Output index */
- int file; /* File_descriptor */
-
- for (j = i = 1; i < argc; i++) { /* Do all arguments */
- switch (*(ap = argv[i])) {
- case '<': /* <file */
- if (freopen(++ap, "r", stdin) == NULL) {
- perror(ap); /* Can't find file */
- exit(IO_ERROR); /* Is a fatal error */
- }
-
- case '>': /* >file or >>file */
- if (*++ap == '>') { /* >>file */
- /*
- * If the file exists, and is writable by us,
- * call freopen to append to the file (using the
- * file's current attributes). Otherwise, create
- * a new file with "vanilla" attributes as if
- * the argument was given as ">filename".
- * access(name, 2) is TRUE if we can write on
- * the specified file.
- */
- if (access(++ap, 2) == 0) {
- if (freopen(ap, "a", stdout) != NULL)
- break; /* Exit case statement */
- perror(ap); /* Error, can't append */
- exit(IO_ERROR); /* After access test */
- } /* If file accessable */
- }
- /*
- * On vms, we want to create the file using "standard"
- * record attributes. create(...) creates the file
- * using the caller's default protection mask and
- * "variable length, implied carriage return"
- * attributes. dup2() associates the file with stdout.
- */
- if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1
- || dup2(file, fileno(stdout)) == -1) {
- perror(ap); /* Can't create file */
- exit(IO_ERROR); /* is a fatal error */
- } /* If '>' creation */
- break; /* Exit case test */
-
- default:
- argv[j++] = ap; /* Not a redirector */
- break; /* Exit case test */
- }
- } /* For all arguments */
- return (j);
- }
- #endif
-
- SHAR_EOF
- if test 7837 -ne "`wc -c < 'archx.c'`"
- then
- echo shar: error transmitting "'archx.c'" '(should have been 7837 characters)'
- fi
- fi
- exit 0
- # End of shell archive
-